#include "gdkmacoseventsource-private.h"
-static gint64 host_to_frame_clock_time (gint64 host_time);
+static gint64 host_to_frame_clock_time (gint64 val);
static gboolean
gdk_display_link_source_prepare (GSource *source,
}
static gint64
-host_to_frame_clock_time (gint64 host_time)
+host_to_frame_clock_time (gint64 val)
{
- static mach_timebase_info_data_t timebase_info;
+ /* NOTE: Code adapted from GLib's g_get_monotonic_time(). */
- /*
- * NOTE:
- *
- * This code is taken from GLib to match g_get_monotonic_time().
- */
- if (G_UNLIKELY (timebase_info.denom == 0))
+ mach_timebase_info_data_t timebase_info;
+
+ /* we get nanoseconds from mach_absolute_time() using timebase_info */
+ mach_timebase_info (&timebase_info);
+
+ if (timebase_info.numer != timebase_info.denom)
{
- /* This is a fraction that we must use to scale
- * mach_absolute_time() by in order to reach nanoseconds.
- *
- * We've only ever observed this to be 1/1, but maybe it could be
- * 1000/1 if mach time is microseconds already, or 1/1000 if
- * picoseconds. Try to deal nicely with that.
- */
- mach_timebase_info (&timebase_info);
-
- /* We actually want microseconds... */
- if (timebase_info.numer % 1000 == 0)
- timebase_info.numer /= 1000;
- else
- timebase_info.denom *= 1000;
-
- /* We want to make the numer 1 to avoid having to multiply... */
- if (timebase_info.denom % timebase_info.numer == 0)
- {
- timebase_info.denom /= timebase_info.numer;
- timebase_info.numer = 1;
- }
- else
- {
- /* We could just multiply by timebase_info.numer below, but why
- * bother for a case that may never actually exist...
- *
- * Plus -- performing the multiplication would risk integer
- * overflow. If we ever actually end up in this situation, we
- * should more carefully evaluate the correct course of action.
- */
- mach_timebase_info (&timebase_info); /* Get a fresh copy for a better message */
- g_error ("Got weird mach timebase info of %d/%d. Please file a bug against GLib.",
- timebase_info.numer, timebase_info.denom);
- }
+#ifdef HAVE_UINT128_T
+ val = ((__uint128_t) val * (__uint128_t) timebase_info.numer) / timebase_info.denom / 1000;
+#else
+ guint64 t_high, t_low;
+ guint64 result_high, result_low;
+
+ /* 64 bit x 32 bit / 32 bit with 96-bit intermediate
+ * algorithm lifted from qemu */
+ t_low = (val & 0xffffffffLL) * (guint64) timebase_info.numer;
+ t_high = (val >> 32) * (guint64) timebase_info.numer;
+ t_high += (t_low >> 32);
+ result_high = t_high / (guint64) timebase_info.denom;
+ result_low = (((t_high % (guint64) timebase_info.denom) << 32) +
+ (t_low & 0xffffffff)) /
+ (guint64) timebase_info.denom;
+ val = ((result_high << 32) | result_low) / 1000;
+#endif
+ }
+ else
+ {
+ /* nanoseconds to microseconds */
+ val = val / 1000;
}
- return host_time / timebase_info.denom;
+ return val;
}